import logging
import getopt
import sys
import smtpd
import asyncore
import warnings
import pprint
#twill, DeprecationWarnings
warnings.filterwarnings("ignore")
import twill
from twill.namespaces import get_twill_glocals
from email import message_from_string
from time import sleep

import conf

CONFIG_LOG_FILE = './pms.log'
CONFIG_FORWARD_TO = None
CONFIG_LISTEN_ON = '127.0.0.1:1025'

class PentestMailServer(smtpd.SMTPServer):

    actions={}
    def set_actions(self, actions):
	self.actions=actions
        logging.debug(pprint.pformat(self.actions))
        pass

    def handle_close(self):
        logging.debug('handle_close called')
        self.close()
   
    def process_message(self, peer, mailfrom, rcpttos, data):
        msg = message_from_string(data)
        if 'Subject' in msg:
            subject = msg['Subject']
        else:
            subject = None
        logging.info('MSG f:%s t:%s h:%s s:%s'%( mailfrom, rcpttos, peer, subject))

        for action,details in self.actions.items():
            logging.debug('testing action: %s'%action)
            if details['bool'](details, mailfrom, rcpttos, subject, msg.get_payload()): #add data
                logging.info('message matches action %s'%action)
                global_dict, local_dict = get_twill_glocals()
                global_dict['from_email'] = mailfrom
                global_dict['to_email'] = rcpttos
                global_dict['subject'] = subject
                global_dict['body'] = msg.get_payload()
                twill.execute_string(details['action'])                

available_params={'-h':{'desc':'this help',           'val':None,       'default':False},
                  '-l':{'desc':'path to log file',    'val':['<path>', '\'-\' for stdout'], 'default':CONFIG_LOG_FILE},
                  '-L':{'desc':'listen on',           'val':['<host>:<port>'], 'default':CONFIG_LISTEN_ON},
}

def parse_config_file(path):
    actions = conf.actions
    return actions

def set_logging(path):
    if path == '-':
        logging.basicConfig(format='[%(asctime)s] %(levelname)s:%(message)s', level=logging.INFO)
    else:
        logging.basicConfig(filename=path, format='[%(asctime)s] %(levelname)s:%(message)s', level=logging.DEBUG)

def parse_opts(args):    
    params = []
    for p,v in available_params.items():
        if v['val']:
            params.append(p.strip('-')+':')
        else:
            params.append(p.strip('-'))
    optlist, args = getopt.getopt(args, ''.join(params))

    optlist = dict(optlist)

    for p,v in available_params.items():
        if p in optlist:
           if v['val']:
               v['value'] = optlist[p]
           else:
               # like -h
               v['value'] = True
        else:
           v['value'] = v['default']         
    
    if available_params['-h']['value']:
       print_help()
       exit()
    
    actions = parse_config_file(None)

    set_logging(available_params['-l']['value'])

    if not available_params['-L']['value']:
        print 'specify proper listening host:port'
        print_help()
        
    l_host,l_port = available_params['-L']['value'].split(':')
 
    try:
        logging.info('Starting PMS on %s:%s press Ctrl+C to stop'%(l_host, l_port))   
        server = PentestMailServer((l_host, int(l_port)), None)
        server.set_actions(actions)

        asyncore.loop() 
    except KeyboardInterrupt:
        logging.info('PMS is stopping')


def print_help():
    print 'PMS - PentestMailServer'
    print ''
    print 'Usage:'
    print '\tpython pms.py <opt>...:'
    for p,v in available_params.items():
        print '\t\t', p, ':', v['desc']
        if v['val']:
            for val in v['val']:
                print '\t\t\t',val
        print '\t\t\tdefault', v['default']


def main():
    parse_opts(sys.argv[1:])

if __name__ == '__main__':
    main()
